package com.toutiao.vssue

import scala.math.sqrt

import org.apache.log4j.Logger

import scala.collection.mutable.ArrayBuffer
import scala.collection.mutable.{HashMap => HMap}

import com.toutiao.issue.SimpleDate
import com.toutiao.issue.WAND

import com.toutiao.score.{Topic,SimScorer,SimpleFactory}
import com.toutiao.model.{Converter,TimeIndex,TimeDict,TimeDB}

import com.twitter.util.{SynchronizedLruMap => LruCache}

class VssTitleCollector (
        val minS: Double = 3.0,
        val mIndex: TimeIndex,
        val mTime: TimeDict,
        val mDB: TimeDB,
        val mID: IDGetter
    ) {
  
  
  private val log = Logger.getLogger(this.getClass.getName)
  
  private val simScorer = new SimScorer
  
  private val CACHE = new LruCache[String,Topic](65536*16)
  
  private def asTopic(x:Document) = {
    val t = new Topic
    t.i = x.name
    t.v = SimpleFactory.norm(x.vs)
    t.s = 1.0
    val title = x.title
    val cc = 3
    val image = 
      if (x.image.size > cc)
        x.image.slice(0,cc)
      else
        x.image
    t.c = x.date
    t.u = x.date
    t.m = Map("t"->title,"e"->image)
    t
  }
  
  def insert(name:String,i:Long,topic:Topic) {
    val t = SimpleDate.format(topic.c).split(" ")(0)
    mDB.insert(t,name,topic)
    mIndex.insert(t,i,topic.m("t"))
    mTime.insert(name,t)
  }
  
  def remove(t:String) = {
    mIndex.remove(t)
    mDB.remove(t)
    mTime.removeTime(t)
  }
  
  private def retrieve(vs:Map[String,Double],S:Double) = {
    val iis = mIndex.getIndex
    val es = iis.map(index => {
      new WAND(index,vs,S)
    })
    val ns = es.par.flatMap(e => e.retrieve).seq
    ns
  }
  
  private def isDataIn(ns:Array[String]) = {
    val nns = ns.filter(!CACHE.contains(_))
    log.info(nns.toBuffer)
    val xs = nns.map(n => {
      val t = mTime(n)
      (n,t,mDB(t).isIn(n))
    }).filter(x => {
      x._3 == false
    }).map(x => {(x._1,x._2)})
    xs
  }
  
  private def getFeature(ns:Array[String]) = {
    val nns = ns.filter(!CACHE.contains(_))
    val xxs = ns.filter(CACHE.contains(_)).map(n => {(n,CACHE(n))}) // Hit Cache
    
    val xs = nns.map(n => {
      val t = mTime(n)
      (n, mDB(t).getValue(n))
    })
    
    val xData = xs.par.map(x => {
      val n = x._1
      //val v = Converter.parseLine(x._2)
      val v = Converter.parseData(x._2)
      (n,v)
    }).seq.toMap
    
    xData++xxs
  }
    
  private def getData(n:String) = {
    if (CACHE.contains(n)){
      CACHE(n)
    }
    else {
      val t = mTime(n)
      val x = mDB(t).getValue(n)
      Converter.parseData(x)
    }
  }
  
  def process(x:Document, S:Double) = {
    val topic = asTopic(x)

    //log.info("Retrieve ...")
    val ns = retrieve(
        topic.m("t").filter(_.size > 1).map(v => { // 不对单字做召回
        	(v,1.0)
        	}).toMap, minS)
        	.toArray.map(_.toString)
    //log.info("Retrieve Done")
    
    val xData = getFeature(ns)
    
    val rs = ns.par.map(n => {
      (n,simScorer.getSimScore(xData(n),topic,S))
    })
    
    val (z,s) = if (rs.size > 0) {
    				rs.maxBy(_._2)
    			}
    			else {
    				("",0.0)
    			}
    
    if (s == S+0.01 || s == S+0.02 || s == S+0.03){
    	log.info(topic.i+" "+z+" "+s)  
    }
    
    if (s >= S) {
      z // Found Similar
    }
    else {
      val i = mID.get 
      val name = new String(i.toString)
      insert(name,i,topic)
      CACHE(name) = topic
      i.toString
    }
        	
    
  }
  
  
}